package deviceConfig

import (
	"context"
	"devops-super/internal/consts"
	"devops-super/internal/model/mymodel"
	"devops-super/internal/service"
	"devops-super/pb"
	"errors"
	"fmt"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/golang/protobuf/proto"
	"github.com/tiger1103/gfast/v3/library/liberr"
	"strconv"
	"strings"
	"time"
)

func (s *sDeviceConfig) SetIotAeParamConfig(ctx context.Context, deviceNo string, copyDevices []string, config *mymodel.AeParamConfItem) (err error) {
	if config == nil {
		return nil
	}
	allSns := make([]string, 0)
	allSns = append(allSns, deviceNo)
	if copyDevices != nil {
		allSns = append(allSns, copyDevices...)
	}
	deviceInfo0, err := service.Device().GetByDeviceNo(ctx, deviceNo)
	if err != nil {
		return err
	}
	if deviceInfo0 == nil || deviceInfo0.Id == 0 {
		err = errors.New("device not exist")
		return err
	}
	aeMeasureConfig := &pb.AeMeasureConfig{
		AeThreshold:       float64(config.AeThreshold),
		AeMeasureSpeed:    uint32(config.AeMeasureSpeed),
		AeMeasureMode:     uint32(config.AeMeasureMode),
		AeEet:             uint32(config.AeEet),
		AeHdt:             uint32(config.AeHdt),
		AeHlt:             uint32(config.AeHlt),
		AeMeasureLength:   uint32(config.AeMeasureLength),
		AeMeasureTimes:    uint32(config.AeMeasureTimes),
		AeMeasureInterval: uint32(config.AeMeasureInterval),
		AeParaEnable:      bool(config.AeParaEnable),
		AeWaveEnable:      bool(config.AeWaveEnable),
		AeSystemTime:      uint32(gtime.Now().Unix()),
		AeMeasureState:    bool(config.AeMeasureState),
	}
	if deviceInfo0.Type == 0 {
		for _, thisSn := range allSns {
			deviceInfo, err := service.Device().GetByDeviceNo(ctx, thisSn)
			if err != nil {
				return err
			}
			if deviceInfo == nil || deviceInfo.DeviceNo == "" {
				continue
			}
			// 生成proto对象
			aeMsg := &pb.SensorMessage{
				NodeId:      thisSn,
				UnixTime:    uint32(gtime.Now().Unix()),
				Microsecond: int32(gtime.Now().Microsecond()),
				Msg:         &pb.SensorMessage_AeMeasureConfig{AeMeasureConfig: aeMeasureConfig},
			}
			pData, err := proto.Marshal(aeMsg)
			if err != nil {
				return err
			}
			err = service.Aeemqx().CommonAePublish(ctx, thisSn, consts.EmqxAeSendType4, pData, &mymodel.EmqxPublishOps{Retained: true, ConfigType: consts.DeviceConfTypeParamConfig})
			if err != nil {
				return err
			}
			productInfo, err := service.Product().GetByProductId(ctx, deviceInfo.ProductId)
			if err != nil || productInfo == nil {
				continue
			}
			if productInfo.ProductKey == consts.ProductKeyM1 {
				go func(thisSn string) {
					time.Sleep(time.Duration(500) * time.Millisecond)
					err = s.RefreshConfig(ctx, thisSn)
					if err != nil {
						return
					}
				}(thisSn)
			}
		}
	} else if deviceInfo0.Type == 2 {
		thisSn := deviceNo
		// 生成proto对象
		aeMsg := &pb.SensorMessage{
			NodeId:      thisSn,
			UnixTime:    uint32(gtime.Now().Unix()),
			Microsecond: int32(gtime.Now().Microsecond()),
			Msg:         &pb.SensorMessage_AeMeasureConfig{AeMeasureConfig: aeMeasureConfig},
			NodeIds:     allSns, //追加所有的
		}
		pData, err := proto.Marshal(aeMsg)
		if err != nil {
			return err
		}
		err = service.Aeemqx().CommonAePublish(ctx, thisSn, consts.EmqxAeSendType4, pData, &mymodel.EmqxPublishOps{Retained: true, ConfigType: consts.DeviceConfTypeParamConfig})
		if err != nil {
			return err
		}
	}
	return
}

func (s *sDeviceConfig) SetIotAeFirConfig(ctx context.Context, deviceNo string, copyDevices []string, config *mymodel.AeFirConfItem) (err error) {
	if config == nil {
		return nil
	}
	allSns := make([]string, 0)
	allSns = append(allSns, deviceNo)
	if copyDevices != nil {
		allSns = append(allSns, copyDevices...)
	}
	deviceInfo0, err := service.Device().GetByDeviceNo(ctx, deviceNo)
	if err != nil {
		return err
	}
	if deviceInfo0 == nil || deviceInfo0.Id == 0 {
		err = errors.New("device not exist")
		return err
	}
	//发送滤波配置命令
	firConfg := &pb.FirConfig{
		FirEnable: uint32(config.FirEnable),
		FirLow:    uint32(config.FirLow),
		FirHigh:   uint32(config.FirHigh),
		FirM2Mode: uint32(config.FirM2Mode),
	}
	if deviceInfo0.Type == 0 {
		for _, thisSn := range allSns {
			deviceInfo, err := service.Device().GetByDeviceNo(ctx, thisSn)
			if err != nil {
				return err
			}
			if deviceInfo == nil || deviceInfo0.Id == 0 {
				continue
			}
			aeMsg2 := &pb.SensorMessage{
				NodeId:      thisSn,
				UnixTime:    uint32(gtime.Now().Unix()),
				Microsecond: int32(gtime.Now().Microsecond()),
				Msg:         &pb.SensorMessage_FirConfig{FirConfig: firConfg},
			}
			pData2, err := proto.Marshal(aeMsg2)
			if err != nil {
				return err
			}
			err = service.Aeemqx().CommonAePublish(ctx, thisSn, consts.EmqxAeSendType4, pData2, &mymodel.EmqxPublishOps{Retained: true, ConfigType: consts.DeviceConfTypeFirConfig})
			if err != nil {
				return err
			}
			productInfo, err := service.Product().GetByProductId(ctx, deviceInfo.ProductId)
			if err != nil || productInfo == nil {
				continue
			}
			if productInfo.ProductKey == consts.ProductKeyM1 {
				go func(thisSn string) {
					time.Sleep(time.Duration(500) * time.Millisecond)
					err = s.RefreshConfig(ctx, thisSn)
					if err != nil {
						return
					}
				}(thisSn)
			}
		}
	} else if deviceInfo0.Type == 2 {
		thisSn := deviceNo
		aeMsg2 := &pb.SensorMessage{
			NodeId:      thisSn,
			UnixTime:    uint32(gtime.Now().Second()),
			Microsecond: int32(gtime.Now().Microsecond()),
			Msg:         &pb.SensorMessage_FirConfig{FirConfig: firConfg},
			NodeIds:     allSns,
		}
		pData2, err := proto.Marshal(aeMsg2)
		if err != nil {
			return err
		}
		err = service.Aeemqx().CommonAePublish(ctx, thisSn, consts.EmqxAeSendType4, pData2, &mymodel.EmqxPublishOps{Retained: true, ConfigType: consts.DeviceConfTypeFirConfig})
		if err != nil {
			return err
		}
	}
	return
}

func (s *sDeviceConfig) SetIotAeDeviceAeFFTConfig(ctx context.Context, deviceNo string, copyDevices []string, config *mymodel.AeFFTConfItem) (err error) {
	if config == nil {
		return nil
	}
	allSns := make([]string, 0)
	allSns = append(allSns, deviceNo)
	if copyDevices != nil {
		allSns = append(allSns, copyDevices...)
	}
	deviceInfo0, err := service.Device().GetByDeviceNo(ctx, deviceNo)
	if err != nil {
		return err
	}
	if deviceInfo0 == nil || deviceInfo0.Id == 0 {
		err = errors.New("device not exist")
		return err
	}
	pbBandItems := make([]*pb.AeFFTConfigBandItem, 0)
	if config.AeFFTConfigBandItems != nil {
		for _, bandItem := range config.AeFFTConfigBandItems {
			pbBandItems = append(pbBandItems, &pb.AeFFTConfigBandItem{
				Index:  bandItem.Index,
				Start:  bandItem.Start,
				End:    bandItem.End,
				Enable: bandItem.Enable,
			})
		}
	}
	aconfig := &pb.AeFFTConfig{
		AeFftEnable:          config.AeFftEnable,
		AeFFTConfigBandItems: pbBandItems,
		Extract:              config.Extract,
	}
	if deviceInfo0.Type == 0 {
		for _, thisSn := range allSns {
			deviceInfo, err := service.Device().GetByDeviceNo(ctx, thisSn)
			if err != nil {
				return err
			}
			if deviceInfo == nil || deviceInfo0.Id == 0 {
				continue
			}
			// 生成proto对象
			aeMsg := &pb.SensorMessage{
				NodeId:      thisSn,
				UnixTime:    uint32(gtime.Now().Unix()),
				Microsecond: int32(gtime.Now().Microsecond()),
				Msg:         &pb.SensorMessage_AeFFTConfig{AeFFTConfig: aconfig},
			}
			pData, err := proto.Marshal(aeMsg)
			if err != nil {
				return err
			}
			err = service.Aeemqx().CommonAePublish(ctx, thisSn, consts.EmqxAeSendType4, pData, &mymodel.EmqxPublishOps{Retained: true, ConfigType: consts.DeviceConfTypeAeFftConfig})
			if err != nil {
				return err
			}
			productInfo, err := service.Product().GetByProductId(ctx, deviceInfo.ProductId)
			if err != nil || productInfo == nil {
				continue
			}
			if productInfo.ProductKey == consts.ProductKeyM1 {
				go func(thisSn string) {
					time.Sleep(time.Duration(500) * time.Millisecond)
					err = s.RefreshConfig(ctx, thisSn)
					if err != nil {
						return
					}
				}(thisSn)
			}
		}
	} else if deviceInfo0.Type == 2 {
		thisSn := deviceNo
		// 生成proto对象
		aeMsg := &pb.SensorMessage{
			NodeId:      thisSn,
			UnixTime:    uint32(gtime.Now().Unix()),
			Microsecond: int32(gtime.Now().Microsecond()),
			Msg:         &pb.SensorMessage_AeFFTConfig{AeFFTConfig: aconfig},
			NodeIds:     allSns,
		}
		pData, err := proto.Marshal(aeMsg)
		if err != nil {
			return err
		}
		err = service.Aeemqx().CommonAePublish(ctx, thisSn, consts.EmqxAeSendType4, pData, &mymodel.EmqxPublishOps{Retained: true, ConfigType: consts.DeviceConfTypeAeFftConfig})
		if err != nil {
			return err
		}
	}
	return
}

// SetIotAeDeviceLevelConfig2 评级配置 v2
func (s *sDeviceConfig) SetIotAeDeviceLevelConfig2(ctx context.Context, deviceNo string, copyDevices []string, config *mymodel.AeLevelConfItem2) (err error) {
	if config == nil {
		return nil
	}
	allSns := make([]string, 0)
	allSns = append(allSns, deviceNo)
	if copyDevices != nil {
		allSns = append(allSns, copyDevices...)
	}
	deviceInfo0, err := service.Device().GetByDeviceNo(ctx, deviceNo)
	if err != nil {
		return err
	}
	if deviceInfo0 == nil || deviceInfo0.Id == 0 {
		err = errors.New("device not exist")
		return err
	}
	aeLevelStrengths := make([]*pb.AeLevelConfigStrengthItem, 0)
	if config.AeLevelStrength != nil {
		for _, item1 := range config.AeLevelStrength {
			thisAeLevelRules := make([]*pb.AeLevelRule, 0)
			if item1.Rules != nil {
				for _, item2 := range item1.Rules {
					thisAeRuleItems := make([]*pb.AeRuleItem, 0)
					if item2.Items != nil {
						for _, item3 := range item2.Items {
							thisAeRuleItem := &pb.AeRuleItem{
								Prop:  item3.Prop,
								Value: item3.Value,
							}
							thisAeRuleItems = append(thisAeRuleItems, thisAeRuleItem)
						}
					}
					thisLevelRule := &pb.AeLevelRule{Items: thisAeRuleItems}
					thisAeLevelRules = append(thisAeLevelRules, thisLevelRule)
				}
			}
			aeLevelStrength := &pb.AeLevelConfigStrengthItem{
				Level: int32(item1.Level),
				Rules: thisAeLevelRules,
			}
			aeLevelStrengths = append(aeLevelStrengths, aeLevelStrength)
		}
	}
	aeLevelActivitys := make([]*pb.AeLevelConfigActivityItem, 0)
	if config.AeLevelActivity != nil {
		for _, item1 := range config.AeLevelActivity {
			thisActivity := &pb.AeLevelConfigActivityItem{
				Level: int32(item1.Level),
				Times: int32(item1.Times),
			}
			aeLevelActivitys = append(aeLevelActivitys, thisActivity)
		}
	}

	aconfig := &pb.LevelConfig{
		Enable:          config.Enable,
		AeLevelStrength: aeLevelStrengths,
		AeLevelActivity: aeLevelActivitys,
		CalTime:         uint32(config.CalTime),
		ReportLevel:     uint32(config.ReportLevel),
		Interval:        uint32(config.Interval),
	}
	if deviceInfo0.Type == 0 {
		for _, thisSn := range allSns {
			deviceInfo, err := service.Device().GetByDeviceNo(ctx, thisSn)
			if err != nil {
				return err
			}
			if deviceInfo == nil || deviceInfo0.Id == 0 {
				continue
			}
			// 生成proto对象
			aeMsg := &pb.SensorMessage{
				NodeId:      thisSn,
				UnixTime:    uint32(gtime.Now().Unix()),
				Microsecond: int32(gtime.Now().Microsecond()),
				Msg:         &pb.SensorMessage_LevelConfig{LevelConfig: aconfig},
			}
			pData, err := proto.Marshal(aeMsg)
			if err != nil {
				return err
			}
			err = service.Aeemqx().CommonAePublish(ctx, thisSn, consts.EmqxAeSendType4, pData, &mymodel.EmqxPublishOps{Retained: true, ConfigType: consts.DeviceConfTypeLevelConfig2})
			if err != nil {
				return err
			}
			productInfo, err := service.Product().GetByProductId(ctx, deviceInfo.ProductId)
			if err != nil || productInfo == nil {
				continue
			}
			if productInfo.ProductKey == consts.ProductKeyM1 {
				go func(thisSn string) {
					time.Sleep(time.Duration(500) * time.Millisecond)
					err = s.RefreshConfig(ctx, thisSn)
					if err != nil {
						return
					}
				}(thisSn)
			}
		}
	} else if deviceInfo0.Type == 2 {
		thisSn := deviceNo
		// 生成proto对象
		aeMsg := &pb.SensorMessage{
			NodeId:      thisSn,
			UnixTime:    uint32(gtime.Now().Unix()),
			Microsecond: int32(gtime.Now().Microsecond()),
			Msg:         &pb.SensorMessage_LevelConfig{LevelConfig: aconfig},
			NodeIds:     allSns,
		}
		pData, err := proto.Marshal(aeMsg)
		if err != nil {
			return err
		}
		err = service.Aeemqx().CommonAePublish(ctx, thisSn, consts.EmqxAeSendType4, pData, &mymodel.EmqxPublishOps{Retained: true, ConfigType: consts.DeviceConfTypeLevelConfig2})
		if err != nil {
			return err
		}
	}
	return
}

// SetIotAeDeviceTimingConfig 1连续采集 2定时采集 3间隔采集 4触发模式
func (s *sDeviceConfig) SetIotAeDeviceTimingConfig(ctx context.Context, deviceNo string, copyDevices []string, config *mymodel.AeTimingConfItem) (err error) {
	if config == nil {
		return nil
	}
	allSns := make([]string, 0)
	allSns = append(allSns, deviceNo)
	if copyDevices != nil {
		allSns = append(allSns, copyDevices...)
	}
	deviceInfo0, err := service.Device().GetByDeviceNo(ctx, deviceNo)
	if err != nil {
		return err
	}
	if deviceInfo0 == nil || deviceInfo0.Id == 0 {
		err = errors.New("device not exist")
		return err
	}
	aetimer := &pb.AeTimer{
		AeTimingIndexMax: 0,
		AeTimingStart:    "",
		AeTimingStop:     "",
	}
	if config.AeTimingType == 2 {
		if config.AeFixedTimingList != nil {
			strS := make([]string, 0)
			strE := make([]string, 0)
			for _, tlist := range config.AeFixedTimingList {
				strS = append(strS, strconv.Itoa(tlist.Range[0]))
				strE = append(strE, strconv.Itoa(tlist.Range[1]))
			}
			aetimer.AeTimingIndexMax = uint32(len(config.AeFixedTimingList))
			aetimer.AeTimingStart = strings.Join(strS, ",")
			aetimer.AeTimingStop = strings.Join(strE, ",")
		}
	}
	crons := make([]*pb.AeCronItem, 0)
	if config.Crons != nil {
		for _, item := range config.Crons {
			crons = append(crons, &pb.AeCronItem{
				Start: item.Start,
				End:   item.End,
				Cron:  item.Cron,
			})
		}
	}
	aconfig := &pb.AeTimingConfig{
		AeTimingEnable: config.AeTimingEnable,
		AeTimingType:   uint32(config.AeTimingType),
		AeTimingLength: uint32(config.AeTimingLength),
		AeTimingSleep:  uint32(config.AeTimingSleep),
		Crons:          crons,
	}
	if config.AeTimingType == 2 {
		aconfig.Msg = &pb.AeTimingConfig_AeTimer{AeTimer: aetimer}
	}
	if deviceInfo0.Type == 0 {
		for _, thisSn := range allSns {
			deviceInfo, err := service.Device().GetByDeviceNo(ctx, thisSn)
			if err != nil {
				return err
			}
			if deviceInfo == nil || deviceInfo0.Id == 0 {
				continue
			}
			// 生成proto对象
			aeMsg := &pb.SensorMessage{
				NodeId:      thisSn,
				UnixTime:    uint32(gtime.Now().Unix()),
				Microsecond: int32(gtime.Now().Microsecond()),
				Msg:         &pb.SensorMessage_AeTimingConfig{AeTimingConfig: aconfig},
			}
			pData, err := proto.Marshal(aeMsg)
			if err != nil {
				return err
			}
			err = service.Aeemqx().CommonAePublish(ctx, thisSn, consts.EmqxAeSendType4, pData, &mymodel.EmqxPublishOps{Retained: true, ConfigType: consts.DeviceConfTypeTimingConfig})
			if err != nil {
				return err
			}
			productInfo, err := service.Product().GetByProductId(ctx, deviceInfo.ProductId)
			if err != nil || productInfo == nil {
				continue
			}
			if productInfo.ProductKey == consts.ProductKeyM1 {
				go func(thisSn string) {
					time.Sleep(time.Duration(500) * time.Millisecond)
					err = s.RefreshConfig(ctx, thisSn)
					if err != nil {
						return
					}
				}(thisSn)
			}
		}
	} else if deviceInfo0.Type == 2 {
		thisSn := deviceNo
		// 生成proto对象
		aeMsg := &pb.SensorMessage{
			NodeId:      thisSn,
			UnixTime:    uint32(gtime.Now().Unix()),
			Microsecond: int32(gtime.Now().Microsecond()),
			Msg:         &pb.SensorMessage_AeTimingConfig{AeTimingConfig: aconfig},
			NodeIds:     allSns,
		}
		pData, err := proto.Marshal(aeMsg)
		if err != nil {
			return err
		}
		err = service.Aeemqx().CommonAePublish(ctx, thisSn, consts.EmqxAeSendType4, pData, &mymodel.EmqxPublishOps{Retained: true, ConfigType: consts.DeviceConfTypeTimingConfig})
		if err != nil {
			return err
		}
	}
	return
}

func (s *sDeviceConfig) SetIotAeDeviceFrpConfig(ctx context.Context, deviceNo string, copyDevices []string, config *mymodel.AeFrpItem) (err error) {
	if config == nil {
		return nil
	}
	allSns := make([]string, 0)
	allSns = append(allSns, deviceNo)
	if copyDevices != nil {
		allSns = append(allSns, copyDevices...)
	}
	deviceInfo0, err := service.Device().GetByDeviceNo(ctx, deviceNo)
	if err != nil {
		return err
	}
	if deviceInfo0 == nil || deviceInfo0.Id == 0 {
		err = errors.New("device not exist")
		return err
	}
	//发送滤波配置命令
	frpConfg := &pb.FrpConfig{
		Enable:               config.Enable,
		ServerIp:             config.ServerIp,
		ServerPort:           config.ServerPort,
		RemotePort:           config.RemotePort,
		TcpMux:               config.TcpMux,
		TcpMuxConnectTimeout: config.TcpMuxConnectTimeout,
		HeartbeatInterval:    config.HeartbeatInterval,
		HeartbeatTimeout:     config.HeartbeatTimeout,
	}
	//要么直连 要么网关才可能发
	if deviceInfo0.Type == 0 || deviceInfo0.Type == 1 {
		for _, thisSn := range allSns {
			deviceInfo, err := service.Device().GetByDeviceNo(ctx, thisSn)
			if err != nil {
				return err
			}
			if deviceInfo == nil || deviceInfo0.Id == 0 {
				continue
			}
			aeMsg2 := &pb.SensorMessage{
				NodeId:      thisSn,
				UnixTime:    uint32(gtime.Now().Unix()),
				Microsecond: int32(gtime.Now().Microsecond()),
				Msg:         &pb.SensorMessage_FrpConfig{FrpConfig: frpConfg},
			}
			pData2, err := proto.Marshal(aeMsg2)
			if err != nil {
				liberr.ErrIsNil(ctx, err, fmt.Sprintf("%v", err))
			}
			err = service.Aeemqx().CommonAePublish(ctx, thisSn, consts.EmqxAeSendType4, pData2, &mymodel.EmqxPublishOps{Retained: false, ConfigType: consts.DeviceConfTypeFrpConfig})
			if err != nil {
				liberr.ErrIsNil(ctx, err, fmt.Sprintf("%v", err))
			}
			productInfo, err := service.Product().GetByProductId(ctx, deviceInfo.ProductId)
			if err != nil || productInfo == nil {
				continue
			}
			if productInfo.ProductKey == consts.ProductKeyM1 {
				go func(thisSn string) {
					time.Sleep(time.Duration(500) * time.Millisecond)
					err = s.RefreshConfig(ctx, thisSn)
					if err != nil {
						return
					}
				}(thisSn)
			}
		}
	}

	return
}

func (s *sDeviceConfig) RefreshConfig(ctx context.Context, deviceNo string) (err error) {
	cmd := consts.AeMqttStateCmd_0
	return s.PushCmdToDevice(ctx, deviceNo, cmd)
}

func (s *sDeviceConfig) PushCmdToDevice(ctx context.Context, deviceNo string, cmd int) (err error) {
	state := &pb.IotDeviceState{
		Cmd: uint32(cmd),
	}
	aeMsg := &pb.SensorMessage{
		NodeId:      deviceNo,
		UnixTime:    uint32(gtime.Now().Unix()),
		Microsecond: int32(gtime.Now().Microsecond()),
		Msg:         &pb.SensorMessage_IotDeviceState{IotDeviceState: state},
	}
	pData, err := proto.Marshal(aeMsg)
	if err != nil {
		return err
	}
	err = service.Aeemqx().CommonAePublish(ctx, deviceNo, consts.EmqxAeSendType4, pData, &mymodel.EmqxPublishOps{Retained: false})
	if err != nil {
		return err
	}
	return
}
